From 33502d3bdec0536289c3975b005506cbd300f186 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Fri, 10 Mar 2006 09:12:22 +0100 Subject: [PATCH] Clean the pending_intr processing sequence and fix some potential bugs. Signed-off-by: Eddie Dong Signed-off-by: Xiaowei Yang --- xen/arch/x86/hvm/vlapic.c | 14 ++++++ xen/arch/x86/hvm/vmx/io.c | 69 +++++++++++++++++------------- xen/arch/x86/hvm/vmx/vmcs.c | 1 + xen/arch/x86/hvm/vmx/vmx.c | 2 + xen/include/asm-x86/hvm/io.h | 1 + xen/include/asm-x86/hvm/vlapic.h | 1 + xen/include/asm-x86/hvm/vmx/vmcs.h | 1 + 7 files changed, 59 insertions(+), 30 deletions(-) diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 10d7284342..89cd82afd7 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -943,6 +943,20 @@ int cpu_get_apic_interrupt(struct vcpu *v, int *mode) return -1; } +int cpu_has_apic_interrupt(struct vcpu* v) +{ + struct vlapic *vlapic = VLAPIC(v); + + if (vlapic && vlapic_enabled(vlapic)) { + int highest_irr = vlapic_find_highest_irr(vlapic); + + if (highest_irr != -1 && highest_irr >= vlapic->processor_priority) { + return 1; + } + } + return 0; +} + void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode) { struct vlapic *vlapic = VLAPIC(v); diff --git a/xen/arch/x86/hvm/vmx/io.c b/xen/arch/x86/hvm/vmx/io.c index 6c129f34e0..38ffa0a5d1 100644 --- a/xen/arch/x86/hvm/vmx/io.c +++ b/xen/arch/x86/hvm/vmx/io.c @@ -86,28 +86,53 @@ interrupt_post_injection(struct vcpu * v, int vector, int type) } static inline void -enable_irq_window(unsigned long cpu_exec_control) +enable_irq_window(struct vcpu *v) { - if (!(cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING)) { - cpu_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; - __vmwrite(CPU_BASED_VM_EXEC_CONTROL, cpu_exec_control); + u32 *cpu_exec_control = &v->arch.hvm_vcpu.u.vmx.exec_control; + + if (!(*cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING)) { + *cpu_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; + __vmwrite(CPU_BASED_VM_EXEC_CONTROL, *cpu_exec_control); } } static inline void -disable_irq_window(unsigned long cpu_exec_control) +disable_irq_window(struct vcpu *v) { - if ( cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING ) { - cpu_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; - __vmwrite(CPU_BASED_VM_EXEC_CONTROL, cpu_exec_control); + u32 *cpu_exec_control = &v->arch.hvm_vcpu.u.vmx.exec_control; + + if ( *cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING ) { + *cpu_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; + __vmwrite(CPU_BASED_VM_EXEC_CONTROL, *cpu_exec_control); } } +static inline int is_interruptibility_state(void) +{ + int interruptibility; + __vmread(GUEST_INTERRUPTIBILITY_INFO, &interruptibility); + return interruptibility; +} + +/* check to see if there is pending interrupt */ +int cpu_has_pending_irq(struct vcpu *v) +{ + struct hvm_domain *plat = &v->domain->arch.hvm_domain; + + /* APIC */ + if ( cpu_has_apic_interrupt(v) ) return 1; + + /* PIC */ + if ( !vlapic_accept_pic_intr(v) ) return 0; + + return plat->interrupt_request; +} + asmlinkage void vmx_intr_assist(void) { int intr_type = 0; int highest_vector; - unsigned long intr_fields, eflags, interruptibility, cpu_exec_control; + unsigned long eflags; struct vcpu *v = current; struct hvm_domain *plat=&v->domain->arch.hvm_domain; struct hvm_virpit *vpit = &plat->vpit; @@ -121,37 +146,21 @@ asmlinkage void vmx_intr_assist(void) pic_set_irq(pic, 0, 1); } - __vmread_vcpu(v, CPU_BASED_VM_EXEC_CONTROL, &cpu_exec_control); - __vmread(VM_ENTRY_INTR_INFO_FIELD, &intr_fields); + if ( !cpu_has_pending_irq(v) ) return; - if (intr_fields & INTR_INFO_VALID_MASK) { - enable_irq_window(cpu_exec_control); - HVM_DBG_LOG(DBG_LEVEL_1, "vmx_intr_assist: intr_fields: %lx", - intr_fields); - return; - } - - __vmread(GUEST_INTERRUPTIBILITY_INFO, &interruptibility); - - if (interruptibility) { - enable_irq_window(cpu_exec_control); - HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility: %lx",interruptibility); + if ( is_interruptibility_state() ) { /* pre-cleared for emulated instruction */ + enable_irq_window(v); + HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility"); return; } __vmread(GUEST_RFLAGS, &eflags); if (irq_masked(eflags)) { - enable_irq_window(cpu_exec_control); + enable_irq_window(v); return; } highest_vector = cpu_get_interrupt(v, &intr_type); - - if (highest_vector == -1) { - disable_irq_window(cpu_exec_control); - return; - } - switch (intr_type) { case VLAPIC_DELIV_MODE_EXT: case VLAPIC_DELIV_MODE_FIXED: diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index b755075063..ce0e8031eb 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -219,6 +219,7 @@ static void vmx_do_launch(struct vcpu *v) error |= __vmwrite(CR0_READ_SHADOW, cr0); error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL, MONITOR_CPU_BASED_EXEC_CONTROLS); + v->arch.hvm_vcpu.u.vmx.exec_control = MONITOR_CPU_BASED_EXEC_CONTROLS; __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (cr4) : ); diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 05a099e2c1..77310e5146 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -595,6 +595,7 @@ static void inline __update_guest_eip(unsigned long inst_len) __vmread(GUEST_RIP, ¤t_eip); __vmwrite(GUEST_RIP, current_eip + inst_len); + __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0); } @@ -2025,6 +2026,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs) case EXIT_REASON_PENDING_INTERRUPT: __vmwrite(CPU_BASED_VM_EXEC_CONTROL, MONITOR_CPU_BASED_EXEC_CONTROLS); + v->arch.hvm_vcpu.u.vmx.exec_control = MONITOR_CPU_BASED_EXEC_CONTROLS; break; case EXIT_REASON_TASK_SWITCH: __hvm_bug(®s); diff --git a/xen/include/asm-x86/hvm/io.h b/xen/include/asm-x86/hvm/io.h index 46698d055c..224f22cc4a 100644 --- a/xen/include/asm-x86/hvm/io.h +++ b/xen/include/asm-x86/hvm/io.h @@ -154,6 +154,7 @@ extern void hvm_io_assist(struct vcpu *v); extern void pic_irq_request(int *interrupt_request, int level); extern void hvm_pic_assist(struct vcpu *v); extern int cpu_get_interrupt(struct vcpu *v, int *type); +extern int cpu_has_pending_irq(struct vcpu *v); // XXX - think about this, maybe use bit 30 of the mfn to signify an MMIO frame. #define mmio_space(gpa) (!VALID_MFN(get_mfn_from_gpfn((gpa) >> PAGE_SHIFT))) diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index 2f8a4f7b14..95ee810a8b 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -209,6 +209,7 @@ static uint32_t inline vlapic_get_base_address(struct vlapic *vlapic) void vlapic_post_injection(struct vcpu* v, int vector, int deliver_mode); +int cpu_has_apic_interrupt(struct vcpu* v); int cpu_get_apic_interrupt(struct vcpu* v, int *mode); extern uint32_t vlapic_update_ppr(struct vlapic *vlapic); diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index 54820bcb2b..703ae090f3 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -69,6 +69,7 @@ struct vmx_msr_state { struct arch_vmx_struct { struct vmcs_struct *vmcs; /* VMCS pointer in virtual. */ unsigned int launch_cpu; /* VMCS is valid on this CPU. */ + u32 exec_control; /* cache of cpu execution control */ unsigned long flags; /* VMCS flags */ unsigned long cpu_cr0; /* copy of guest CR0 */ unsigned long cpu_shadow_cr0; /* copy of guest read shadow CR0 */ -- 2.30.2